using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Collections.Generic;
using UnityEngine;

namespace Z1029.PhiPlayer.OpenSource
{
    public class ChartReader
    {
        public static Chart ReadChart(string file)
        {
            if (file.StartsWith("BinaryChartPath:"))
            {
                file = file.Substring(16);
                Debug.Log(file);
                BinaryFormatter bf = new BinaryFormatter();
                FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read);
                Chart c = (Chart)bf.Deserialize(fs);
                byte[] bs = new byte[fs.Length];
                fs.Read(bs, 0, (int)fs.Length);
                fs.Close();
                LevelInfo.currentInfo.levelMd5 = SecurityUtils.Md5Sum(bs);
                return c;
            }
            else return JsonUtility.FromJson<Chart>(file);
        }
    }

    [Serializable]
    public class Chart
    {
        public string chartVersion;
        public float offset;
        public int numOfNotes;
        public JudgeLineSet[] judgeLineList;
    }

    [Serializable]
    public class SpeedEvent
    {
        public float startTime;
        public float endTime;
        public float value;
    }

    [Serializable]
    public class JudgeLineSet
    {
        public float bpm;
        public SpeedEvent[] speedEvents;
        public Note.NoteData[] notesAbove;
        public Note.NoteData[] notesBelow;
        public ValueSet[] alphaEvents;
        public ValueSet[] moveEvents;
        public ValueSet[] rotateEvents;
    }

    [Serializable]
    public class ValueSet
    {
        public float startTime;
        public float endTime;
        public float start;
        public float end;
        public float start2;
        public float end2;
    }

    public class PhigrosChartReader : ChartReader
    {
        public static Chart ReadChart(string file)
        {
            Chart chart = new Chart();
            PhigrosChart gameChart = JsonUtility.FromJson<PhigrosChart>(file);
            int ver = gameChart.formatVersion;

            int notesCount = 0;
            chart.numOfNotes = gameChart.numOfNotes;
            chart.offset = gameChart.offset;
            chart.chartVersion = "Phigros.v" + ver.ToString();
            chart.judgeLineList = new Z1029.PhiPlayer.OpenSource.JudgeLineSet[gameChart.judgeLineList.Length];

            for (int i = 0; i < gameChart.judgeLineList.Length; i++)
            {
                chart.judgeLineList[i] = new Z1029.PhiPlayer.OpenSource.JudgeLineSet();
                chart.judgeLineList[i].notesAbove = new Note.NoteData[gameChart.judgeLineList[i].notesAbove.Length];
                for (int j = 0; j < gameChart.judgeLineList[i].notesAbove.Length; j++)
                {
                    Note.NoteData eve = new Note.NoteData();
                    int type = gameChart.judgeLineList[i].notesAbove[j].type;
                    switch (type)
                    {
                        case 1:
                            eve.type = NoteType.Click;
                            break;
                        case 4://4
                            eve.type = NoteType.Flick;
                            break;
                        case 3://3
                            eve.type = NoteType.Hold;
                            break;
                        case 2://2
                            eve.type = NoteType.Drag;
                            break;
                    }
                    eve.beatTime = gameChart.judgeLineList[i].notesAbove[j].time;
                    eve.time = gameChart.judgeLineList[i].notesAbove[j].time * (60 / gameChart.judgeLineList[i].bpm) / 32;
                    eve.positionX = gameChart.judgeLineList[i].notesAbove[j].positionX;
                    eve.index = notesCount;
                    //eve.speed = gameChart.judgeLineList[i].notesAbove[j].speed * (gameChart.formatVersion == 1 ? gameChart.judgeLineList[i].bpm / 16 : gameChart.judgeLineList[i].bpm / 16);
                    eve.speed = gameChart.judgeLineList[i].notesAbove[j].speed * 12;
                    //if (ipad) eve.speed *=1.5f
                    if (type == 3) eve.speed /= GetJudgelineSpeed((eve.beatTime + gameChart.judgeLineList[i].notesAbove[j].holdTime / 2), gameChart.judgeLineList[i].speedEvents) == 0 ? 1 : GetJudgelineSpeed((eve.beatTime + gameChart.judgeLineList[i].notesAbove[j].holdTime / 2), gameChart.judgeLineList[i].speedEvents);
                    eve.beatHoldTime = (int)gameChart.judgeLineList[i].notesAbove[j].holdTime;
                    chart.judgeLineList[i].notesAbove[j] = eve;
                    //notesManager.InstantiateNote(gameChart.judgeLineList[i].notesAbove[j].type, eve, judgelines[i], Note.Direction.Above);
                    notesCount++;
                }
                chart.judgeLineList[i].notesBelow = new Note.NoteData[gameChart.judgeLineList[i].notesBelow.Length];
                for (int k = 0; k < gameChart.judgeLineList[i].notesBelow.Length; k++)
                {
                    Note.NoteData eve2 = new Note.NoteData();
                    int type = gameChart.judgeLineList[i].notesBelow[k].type;
                    switch (type)
                    {
                        case 1:
                            eve2.type = NoteType.Click;
                            break;
                        case 4://4
                            eve2.type = NoteType.Flick;
                            break;
                        case 3://3
                            eve2.type = NoteType.Hold;
                            break;
                        case 2://2
                            eve2.type = NoteType.Drag;
                            break;
                    }
                    eve2.beatTime = gameChart.judgeLineList[i].notesBelow[k].time;
                    eve2.time = gameChart.judgeLineList[i].notesBelow[k].time * (60 / gameChart.judgeLineList[i].bpm) / 32;
                    eve2.positionX = gameChart.judgeLineList[i].notesBelow[k].positionX;
                    //eve2.speed = gameChart.judgeLineList[i].notesBelow[k].speed * (gameChart.formatVersion == 1 ? gameChart.judgeLineList[i].bpm / 16 : gameChart.judgeLineList[i].bpm / 16);
                    eve2.speed = gameChart.judgeLineList[i].notesBelow[k].speed * 12;
                    //if (ipad) eve2.speed *= 1.2f;
                    eve2.index = notesCount;
                    if (type == 3) eve2.speed /= GetJudgelineSpeed((eve2.beatTime + gameChart.judgeLineList[i].notesBelow[k].holdTime / 2), gameChart.judgeLineList[i].speedEvents) == 0 ? 1 : GetJudgelineSpeed((eve2.beatTime + gameChart.judgeLineList[i].notesBelow[k].holdTime / 2), gameChart.judgeLineList[i].speedEvents);
                    eve2.beatHoldTime = (int)gameChart.judgeLineList[i].notesBelow[k].holdTime;
                    chart.judgeLineList[i].notesBelow[k] = eve2;
                    //notesManager.InstantiateNote(gameChart.judgeLineList[i].notesBelow[k].type, eve2, judgelines[i], Note.Direction.Below);
                    notesCount++;
                }
            }

            for (int i = 0; i < gameChart.judgeLineList.Length; i++)
            {
                chart.judgeLineList[i].bpm = gameChart.judgeLineList[i].bpm;
                chart.judgeLineList[i].speedEvents = new SpeedEvent[gameChart.judgeLineList[i].speedEvents.Length];
                chart.judgeLineList[i].moveEvents = new ValueSet[gameChart.judgeLineList[i].judgeLineMoveEvents.Length];
                chart.judgeLineList[i].rotateEvents = new ValueSet[gameChart.judgeLineList[i].judgeLineRotateEvents.Length];
                chart.judgeLineList[i].alphaEvents = new ValueSet[gameChart.judgeLineList[i].judgeLineDisappearEvents.Length];
                ValueSet[] moveSets = chart.judgeLineList[i].moveEvents;
                SpeedEvent[] speedSets = chart.judgeLineList[i].speedEvents;
                ValueSet[] rotateSets = chart.judgeLineList[i].rotateEvents;
                ValueSet[] alphaSets = chart.judgeLineList[i].alphaEvents;

                for (int j = 0; j < chart.judgeLineList[i].speedEvents.Length; j++)
                {
                    speedSets[j] = new SpeedEvent();
                    float start = gameChart.judgeLineList[i].speedEvents[j].startTime;
                    float end = gameChart.judgeLineList[i].speedEvents[j].endTime;
                    float bpm = gameChart.judgeLineList[i].bpm;
                    speedSets[j].startTime = (float)Utils.GetTimeFromBeatTime(start, bpm);
                    speedSets[j].endTime = (float)Utils.GetTimeFromBeatTime(end, bpm);
                    //if (gameChart.formatVersion == 1) speedSets[j].value = line.speeds[j].value * 10;
                    speedSets[j].value = gameChart.judgeLineList[i].speedEvents[j].value;
                    //line.speeds[j].startTime = line.speeds[j].startTime * (60 / gameChart.judgeLineList[i].bpm) / 32;
                }
                chart.judgeLineList[i].speedEvents = speedSets;

                for (int j = 0; j < chart.judgeLineList[i].moveEvents.Length; j++)
                {
                    ValueSet value = gameChart.judgeLineList[i].judgeLineMoveEvents[j];
                    float bpm = gameChart.judgeLineList[i].bpm;
                    float startT = gameChart.judgeLineList[i].judgeLineMoveEvents[j].startTime;
                    float endT = gameChart.judgeLineList[i].judgeLineMoveEvents[j].endTime;
                    float start = gameChart.judgeLineList[i].judgeLineMoveEvents[j].start;
                    float end = gameChart.judgeLineList[i].judgeLineMoveEvents[j].end;
                    float start2 = gameChart.judgeLineList[i].judgeLineMoveEvents[j].start2;
                    float end2 = gameChart.judgeLineList[i].judgeLineMoveEvents[j].end2;
                    value.startTime = (float)Utils.GetTimeFromBeatTime(startT, bpm);
                    value.endTime = (float)Utils.GetTimeFromBeatTime(endT, bpm);
                    if (ver == 3)
                    {
                        value.start = (start - 0.5f) * 18;
                        value.end = (end - 0.5f) * 18;
                        value.start2 = (start2 - 0.5f) * 10;
                        value.end2 = (end2 - 0.5f) * 10;
                    }
                    else if (ver == 1)
                    {

                        float num = gameChart.judgeLineList[i].judgeLineMoveEvents[j].startTime * (60 / gameChart.judgeLineList[i].bpm) / 32;
                        float num2 = gameChart.judgeLineList[i].judgeLineMoveEvents[j].endTime * (60 / gameChart.judgeLineList[i].bpm) / 32;
                        float num3 = gameChart.judgeLineList[i].judgeLineMoveEvents[j].start;
                        float num4 = gameChart.judgeLineList[i].judgeLineMoveEvents[j].end;
                        value.start = Mathf.FloorToInt(num3 / 1000) - 440;
                        value.end = Mathf.FloorToInt(num4 / 1000) - 440;
                        value.start2 = num3 - Mathf.FloorToInt(num3 / 1000) * 1000 - 260;
                        value.end2 = num4 - Mathf.FloorToInt(num4 / 1000) * 1000 - 260;
                        value.start /= 55;
                        value.end /= 55;
                        value.start2 /= 52;
                        value.end2 /= 52;
                    }
                    moveSets[j] = value;
                }
                chart.judgeLineList[i].moveEvents = moveSets;

                for (int j = 0; j < chart.judgeLineList[i].rotateEvents.Length; j++)
                {
                    ValueSet value = gameChart.judgeLineList[i].judgeLineRotateEvents[j];
                    float bpm = gameChart.judgeLineList[i].bpm;
                    float startT = gameChart.judgeLineList[i].judgeLineRotateEvents[j].startTime;
                    float endT = gameChart.judgeLineList[i].judgeLineRotateEvents[j].endTime;
                    float start = gameChart.judgeLineList[i].judgeLineRotateEvents[j].start;
                    float end = gameChart.judgeLineList[i].judgeLineRotateEvents[j].end;
                    float start2 = gameChart.judgeLineList[i].judgeLineRotateEvents[j].start2;
                    float end2 = gameChart.judgeLineList[i].judgeLineRotateEvents[j].end2;
                    value.startTime = (float)Utils.GetTimeFromBeatTime(startT, bpm);
                    value.endTime = (float)Utils.GetTimeFromBeatTime(endT, bpm);
                    rotateSets[j] = value;
                }
                chart.judgeLineList[i].rotateEvents = rotateSets;

                for (int j = 0; j < chart.judgeLineList[i].alphaEvents.Length; j++)
                {
                    ValueSet value = gameChart.judgeLineList[i].judgeLineDisappearEvents[j];
                    float start = gameChart.judgeLineList[i].judgeLineDisappearEvents[j].startTime;
                    float end = gameChart.judgeLineList[i].judgeLineDisappearEvents[j].endTime;
                    float bpm = gameChart.judgeLineList[i].bpm;
                    value.startTime = (float)Utils.GetTimeFromBeatTime(start, bpm);
                    value.endTime = (float)Utils.GetTimeFromBeatTime(end, bpm);
                    alphaSets[j] = value;
                    //line.speeds[j].startTime = line.speeds[j].startTime * (60 / gameChart.judgeLineList[i].bpm) / 32;
                }
                chart.judgeLineList[i].alphaEvents = alphaSets;
            }

            return chart;
        }

        public static float GetJudgelineSpeed(float time, SpeedEvent[] sp)
        {
            float result = 0;
            for (int i = 0; i < sp.Length; i++)
            {
                SpeedEvent sppp = sp[i];
                if (sppp.startTime < time && sppp.endTime > time) result = sppp.value;
            }
            return result;
        }

        [Serializable]
        public class PhigrosChart
        {
            public int formatVersion;
            public float offset;
            public int numOfNotes;
            public JudgeLineSet[] judgeLineList;
        }

        [Serializable]
        public class JudgeLineSet
        {
            public int numOfNotes;
            public int numOfNotesAbove;
            public int numOfNotesBelow;
            public float bpm;
            public SpeedEvent[] speedEvents;
            public NoteSet[] notesAbove;
            public NoteSet[] notesBelow;
            public ValueSet[] judgeLineDisappearEvents;
            public ValueSet[] judgeLineMoveEvents;
            public ValueSet[] judgeLineRotateEvents;
        }

        [Serializable]
        public class NoteSet
        {
            public int type;
            public int time;
            public float positionX;
            public float holdTime;
            public float speed;
            public float floorPosition;
            public bool isJudged;
            public bool isJudgedForFlick;
            public float realTime;
            public int judgeLineIndex;
            public int noteIndex;
        }
    }

    public class PECChartReader : ChartReader
    {
        public static bool UseFakeNotes = false;

        public static bool UseEase = false;

        public static EaseUtility.Ease ParseEase(string s)
    {
        int type = int.Parse(s);
        switch (type)
        {
            case 1:
                return EaseUtility.Ease.Linear;
                break;
            case 2:
                return EaseUtility.Ease.OutSine;
                break;
            case 3:
                return EaseUtility.Ease.InSine;
                break;
            case 4:
                return EaseUtility.Ease.OutQuad;
                break;
            case 5:
                return EaseUtility.Ease.InQuad;
                break;
            case 6:
                return EaseUtility.Ease.InOutSine;
                break;
            case 7:
                return EaseUtility.Ease.InOutQuad;
                break;
            case 8:
                return EaseUtility.Ease.OutCubic;
                break;
            case 9:
                return EaseUtility.Ease.InCubic;
                break;
            case 10:
                return EaseUtility.Ease.OutQuart;
                break;
            case 11:
                return EaseUtility.Ease.InQuart;
                break;
            case 12:
                return EaseUtility.Ease.InOutCubic;
                break;
            case 13:
                return EaseUtility.Ease.InOutQuart;
                break;
            case 14:
                return EaseUtility.Ease.OutQuint;
                break;
            case 15:
                return EaseUtility.Ease.InQuint;
                break;
            case 16:
                return EaseUtility.Ease.OutExpo;
                break;
            case 17:
                return EaseUtility.Ease.InExpo;
                break;
            case 18:
                return EaseUtility.Ease.OutCirc;
                break;
            case 19:
                return EaseUtility.Ease.InCirc;
                break;
            case 20:
                return EaseUtility.Ease.OutBack;
                break;
            case 21:
                return EaseUtility.Ease.InBack;
                break;
            case 22:
                return EaseUtility.Ease.InOutCirc;
                break;
            case 23:
                return EaseUtility.Ease.InOutBack;
                break;
            case 24:
                return EaseUtility.Ease.OutElastic;
                break;
            case 25:
                return EaseUtility.Ease.InElastic;
                break;
            case 26:
                return EaseUtility.Ease.OutBounce;
                break;
            case 27:
                return EaseUtility.Ease.InBounce;
                break;
            case 28:
                return EaseUtility.Ease.InOutBounce;
                break;
            case 29:
                return EaseUtility.Ease.InOutElastic;
                break;

            default: return EaseUtility.Ease.Linear;
        }
    }

         [Serializable]
    public class valueSet : ValueSet, IComparable<valueSet>
    {
        [NonSerialized]
        public EaseUtility.Ease? easeType = null;
        public int CompareTo(valueSet other)
        {
            if (other.startTime > this.startTime)
                return -1;
            else if (other.startTime < this.startTime)
                return 1;
            else if (other.startTime == this.endTime/*一定成立*/ && other.endTime>this.endTime)
                return -1;
            else return 0;
        }
    }

        [Serializable]
        public class speedEvent : SpeedEvent, IComparable<speedEvent>
        {
            public int CompareTo(speedEvent other)
            {
                if (other.startTime > this.startTime)
                    return -1;
                else if (other.startTime < this.startTime)
                    return 1;
                else return 0;
            }
        }

        static List<valueSet> FillValues(List<valueSet> vs, float bpm, bool removeSameTime = false)
    {
        vs.Sort();
        if (vs.Count == 0)
            return vs;
        if (vs.Count == 1)
            return vs;
        if (vs.Count > 1)
        {
            for (int i = 0; i < vs.Count; i++)
            {
                if (i == 0)
                    continue;
                if (i > 100000)
                {
                    throw new OutOfMemoryException();
                    break;
                }
                if (vs[i - 1].endTime < vs[i].startTime)
                {
                    vs.Insert(i, new valueSet
                    {
                        startTime = vs[i - 1].endTime,
                        endTime = vs[i].startTime,
                        start = vs[i - 1].end,
                        start2 = vs[i - 1].end2,
                        end = vs[i - 1].end,
                        end2 = vs[i - 1].end2,
                    });
                }
                else if(vs[i - 1].endTime > vs[i].startTime)
                {
                    Debug.LogError($"转换错误！，lastevent = {JsonUtility.ToJson(vs[i - 1],true)},next = {JsonUtility.ToJson(vs[i],true)},index = {i}");
                }
            }
            if (!removeSameTime) return vs;
            for (int i = 0; i < vs.Count; i++)
            {
                if (i == 0)
                    continue;
                if (i > 100000)
                {
                    throw new OutOfMemoryException();
                }
                if (vs[i].endTime == vs[i].startTime)
                {
                    vs.Remove(vs[i]);
                    
                }
            }
        }
        
        return vs;
    }

    static List<valueSet> EaseValues(List<valueSet> vs, float bpm)
    {
        vs.Sort();
        if (vs.Count == 0)
            return vs;
        if (vs.Count == 1)
            return vs;
        if (vs.Count > 1)
        {
            for (int i = 0; i < vs.Count; i++)
            {
                if (i == 0)
                    continue;
                if (i > 100000)
                {
                    throw new OutOfMemoryException();
                }
                if (vs[i].easeType != null && vs[i].easeType != EaseUtility.Ease.Linear)
                {
                    if (i >= vs.Count) break;
                    valueSet vss = vs[i];
                    vss.start = vs[i - 1].end;
                    vss.start2 = vs[i - 1].end2;
                    int startTime = Utils.GetBeatTimeFromTime(vss.startTime, bpm);
                    int endTime = Utils.GetBeatTimeFromTime(vss.endTime, bpm);

                    if (endTime - startTime <= 1)
                    {
                        vs[i].easeType = null;
                        continue;
                    }

                    List<valueSet> qwq = new List<valueSet>();
                    for (int j = 0; j < endTime - startTime - 1; j++)
                    {
                        float nt = j / (float)(endTime - startTime);
                        float ease = EaseUtility.Evaluate(vss.easeType.Value, j, (endTime - startTime));
                        float easeNext = EaseUtility.Evaluate(vss.easeType.Value, j + 1, (endTime - startTime));
                        qwq.Add(new valueSet
                        {
                            startTime = (float)Utils.GetTimeFromBeatTime(j + startTime, bpm),
                            endTime = (float)Utils.GetTimeFromBeatTime(j + startTime + 1, bpm),
                            start = vss.start + (vss.end - vss.start) * ease,
                            start2 = vss.start2 + (vss.end2 - vss.start2) * ease,
                            end = vss.start + (vss.end - vss.start) * easeNext,
                            end2 = vss.start2 + (vss.end2 - vss.start2) * easeNext,
                            easeType = null
                        });
                    }
                    if (qwq.Count <= 2)
                    {
                        vs[i].easeType = null;
                        continue;
                    }
                    float last1;
                    float last2;
                    last1 = qwq[qwq.Count - 1].end;
                    last2 = qwq[qwq.Count - 1].end2;
                    qwq.Add(new valueSet
                    {
                        startTime = (float)Utils.GetTimeFromBeatTime(endTime - 1, bpm),
                        endTime = (float)Utils.GetTimeFromBeatTime(endTime, bpm),
                        start = last1,
                        start2 = last2,
                        end = vss.end,
                        end2 = vss.end2,
                        easeType = null
                    });
                    vs.Remove(vs[i]);
                    vs.InsertRange(i, qwq);
                }
            }
        }
        return vs;
    }

        public static Chart ReadChart(string file)
        {
            Utils.AndroidToastStringShow("The \".pec\" file is not fully support.");
        if (File.Exists(FileManager.ResourcesPath + "/PecReaderSettings.txt"))
        {
            string set = (FileManager.ResourcesPath + "/PecReaderSettings.txt").Trim();
            foreach (string s in set.Split('\n'))
            {
                string[] ss = s.Trim().Split(' ');
                if (ss.Length == 2)
                {
                    switch (ss[0].Trim())
                    {
                        case "UseFakeNote": UseFakeNotes = ss[1] == "true"; if (ss[1] == "true") Utils.AndroidToastStringShow("UseFakeNote"); break;
                    }
                }
            }
            if (set.Contains("UseFakeNote true")) UseFakeNotes = true;
        }
        else
        {
            try
            {
                File.WriteAllText(PlayerPrefs.GetString("ResourcesPath") + "/PecReaderSettings.txt",
     @"UseFakeNote false
");
            }
            catch { }
            UseFakeNotes = false;
        }
        Chart chart = new Chart();
        chart.chartVersion = "PEC";
        chart.offset = 0;
        chart.judgeLineList = new JudgeLineSet[100];//最多支持100条判定线
        int judgelineCount = 0;
        string[] lines = file.Split('\n');
        for (int i = 0; i < 100; i++)
        {
            chart.judgeLineList[i] = new JudgeLineSet();
            chart.judgeLineList[i].bpm = float.Parse(lines[1].Split(' ')[2]);
            chart.judgeLineList[i].rotateEvents = new valueSet[0];
            chart.judgeLineList[i].alphaEvents = new valueSet[0];
            chart.judgeLineList[i].moveEvents = new valueSet[0];
            chart.judgeLineList[i].speedEvents = new SpeedEvent[1];
            chart.judgeLineList[i].speedEvents[0] = new SpeedEvent()
            {
                startTime = 0,
                endTime = 99999,
                value = 1
            };
        }
        float bpm = float.Parse(lines[1].Split(' ')[2]);
        Debug.Log(lines[1].Split(' ')[2]);
        int noteCount = 0;
        List<List<Note.NoteData>> aboves = new List<List<Note.NoteData>>();
        List<List<Note.NoteData>> belows = new List<List<Note.NoteData>>();
        List<List<valueSet>> moves = new List<List<valueSet>>();
        List<List<valueSet>> rotates = new List<List<valueSet>>();
        List<List<valueSet>> alphas = new List<List<valueSet>>();
        List<List<speedEvent>> speeds = new List<List<speedEvent>>();
        for (int i = 0; i < 100; i++)//初始化
        {
            aboves.Add(new List<Note.NoteData>());
            belows.Add(new List<Note.NoteData>());
            moves.Add(new List<valueSet>());
            rotates.Add(new List<valueSet>());
            alphas.Add(new List<valueSet>());
            speeds.Add(new List<speedEvent>());
        }
        foreach (string line in lines)
        {
            if (line.Contains("#") || line.Contains("&"))//忽略大小
                continue;
            try
            {
                if (line.StartsWith("n") || line.StartsWith("c"))
                {
                    if (int.Parse(line.Split(' ')[1].Trim()) > judgelineCount)
                        judgelineCount = int.Parse(line.Split(' ')[1].Trim());
                }
            }
            catch { }
#if !UNITY_EDITOR
            try
            {
#endif
            if (line.StartsWith("n"))//Note
            {
                char t = line.ToCharArray()[1];
                NoteType tp = NoteType.Click;
                switch (t)
                {
                    case '1': tp = NoteType.Click; break;
                    case '2': tp = NoteType.Hold; break;
                    case '3': tp = NoteType.Flick; break;
                    case '4': tp = NoteType.Drag; break;
                }
                int dir = (int)(float.Parse(line.Split(' ')[4].Trim()));
                Note.NoteData ns = new Note.NoteData()
                {
                    type = tp,
                    beatTime = (int)(float.Parse(line.Split(' ')[2].Trim()) * 32),
                    positionX = float.Parse(line.Split(' ')[3].Trim()) / 1024 * 8.9f,
                    speed = 12,
                    beatHoldTime = 0
                };
                if (tp == NoteType.Hold)
                {
                    ns = new Note.NoteData()
                    {
                        type = tp,
                        beatTime = (int)(float.Parse(line.Split(' ')[2].Trim()) * 32),
                        positionX = float.Parse(line.Split(' ')[4].Trim()) / 1024 * 8.9f,
                        speed = 12,
                        beatHoldTime = (int)(float.Parse(line.Split(' ')[3].Trim()) * 32) - (int)(float.Parse(line.Split(' ')[2].Trim()) * 32)
                    };
                    dir = (int)(float.Parse(line.Split(' ')[5].Trim()));
                }
                if (!UseFakeNotes)
                {
                    if (tp != NoteType.Hold)
                    {
                        if ((int.Parse(line.Split(' ')[5].Trim())) == 1)
                        {
                            //Utils.AndroidToastStringShow("Fake notes is ignored.");
                            continue;
                        }
                    }
                    if (tp == NoteType.Hold)
                    {
                        if ((int.Parse(line.Split(' ')[6].Trim())) == 1)
                        {
                            //Utils.AndroidToastStringShow("Fake notes is ignored.");
                            continue;
                        }
                    }
                }
                else
                {
                    if (tp != NoteType.Hold)
                    {
                        if ((int.Parse(line.Split(' ')[5].Trim())) == 1)
                        {
                            //ns.speed = 0;
                        }
                    }
                    if (tp == NoteType.Hold)
                    {
                        if ((int.Parse(line.Split(' ')[6].Trim())) == 1)
                        {
                            //ns.speed = 0;
                        }
                    }
                }
                if (dir == 1) aboves[(int.Parse(line.Split(' ')[1].Trim()))].Add(ns);
                else belows[(int.Parse(line.Split(' ')[1].Trim()))].Add(ns);
                noteCount++;
            }
            else if (line.StartsWith("cv"))//velocity
            {
                int index = int.Parse(line.Split(' ')[1]);
                speedEvent se = new speedEvent()
                {
                    startTime = (float)Utils.GetTimeFromBeatTime(float.Parse(line.Split(' ')[2]) * 32, bpm),
                    endTime = 0,
                    value = float.Parse(line.Split(' ')[3]) / 7.0f
                };
                int ssss = speeds[index].Count;
                speeds[index].Add(se);
            }
            else if (line.StartsWith("cp"))//move
            {
                int index = int.Parse(line.Split(' ')[1]);
                if (index >= 100) index = 100;
                valueSet v = new valueSet()
                {
                    startTime = (float)Utils.GetTimeFromBeatTime(float.Parse(line.Split(' ')[2]) * 32, bpm),
                    endTime = (float)Utils.GetTimeFromBeatTime(float.Parse(line.Split(' ')[2]) * 32, bpm),
                    start = ((float.Parse(line.Split(' ')[3]) / 2048f) - 0.5f) * 18,
                    start2 = ((float.Parse(line.Split(' ')[4]) / 1400f) - 0.5f) * 10,
                    end = ((float.Parse(line.Split(' ')[3]) / 2048f) - 0.5f) * 18,
                    end2 = ((float.Parse(line.Split(' ')[4]) / 1400f) - 0.5f) * 10,
                    easeType = null
                };
                moves[index].Add(v);
            }
            else if (line.StartsWith("cm"))//move
            {
                int index = int.Parse(line.Split(' ')[1]);
                if (index >= 100) index = 100;
                moves[index].Sort();

                valueSet v = new valueSet()
                {
                    startTime = (float)Utils.GetTimeFromBeatTime((float.Parse(line.Split(' ')[2]) * 32), bpm),
                    endTime = (float)Utils.GetTimeFromBeatTime((float.Parse(line.Split(' ')[3]) * 32), bpm),
                    end = ((float.Parse(line.Split(' ')[4]) / 2048f) - 0.5f) * 18,
                    end2 = ((float.Parse(line.Split(' ')[5]) / 1400f) - 0.5f) * 10,
                    start = float.NaN,
                    start2 = float.NaN,
                    easeType = ParseEase(line.Split(' ')[6])
                };
                moves[index].Add(v);
            }
            else if (line.StartsWith("cf"))//alpha
            {

                int index = int.Parse(line.Split(' ')[1]);
                if (index >= 100) index = 100;
                valueSet v = new valueSet()
                {
                    startTime = (float)Utils.GetTimeFromBeatTime(float.Parse(line.Split(' ')[2]) * 32, bpm),
                    endTime = (float)Utils.GetTimeFromBeatTime(float.Parse(line.Split(' ')[3]) * 32, bpm),
                    start = float.NaN,
                    end = float.Parse(line.Split(' ')[4]) / 255f,
                    easeType = null
                };
                alphas[index].Add(v);
            }
            else if (line.StartsWith("ca"))//alpha
            {
                int index = int.Parse(line.Split(' ')[1]);
                if (index >= 100) index = 100;
                valueSet v = new valueSet()
                {
                    startTime = (float)Utils.GetTimeFromBeatTime(float.Parse(line.Split(' ')[2]) * 32, bpm),
                    endTime = (float)Utils.GetTimeFromBeatTime(float.Parse(line.Split(' ')[2]) * 32, bpm),
                    end = float.Parse(line.Split(' ')[3]) / 255f,
                    start = float.Parse(line.Split(' ')[3]) / 255f,
                    easeType = null
                };
                alphas[index].Add(v);
            }

            else if (line.StartsWith("cr"))//rotate
            {
                int index = int.Parse(line.Split(' ')[1]);
                if (index >= 100) index = 100;
                valueSet v = new valueSet()
                {
                    startTime = (float)Utils.GetTimeFromBeatTime(float.Parse(line.Split(' ')[2]) * 32, bpm),
                    endTime = (float)Utils.GetTimeFromBeatTime(float.Parse(line.Split(' ')[3]) * 32, bpm),
                    start = float.NaN,
                    end = -float.Parse(line.Split(' ')[4]),
                    easeType = ParseEase(line.Split(' ')[5])
                };
                rotates[index].Add(v);
            }
            else if (line.StartsWith("cd"))//rotate
            {
                int index = int.Parse(line.Split(' ')[1]);
                if (index >= 100) index = 100;
                valueSet v = new valueSet()
                {
                    startTime = (float)Utils.GetTimeFromBeatTime(float.Parse(line.Split(' ')[2]) * 32, bpm),
                    endTime = (float)Utils.GetTimeFromBeatTime(float.Parse(line.Split(' ')[2]) * 32, bpm),
                    start = -float.Parse(line.Split(' ')[3]),
                    end = -float.Parse(line.Split(' ')[3]),
                    easeType = null
                };
                rotates[index].Add(v);
            }
#if !UNITY_EDITOR
            }
            catch (Exception e)
            {
                Utils.AndroidToastStringShow("Read error at line : " + line + ",Ex : " + e.Message);
            }
#endif
        }

        chart.numOfNotes = noteCount;
        chart.judgeLineList = new JudgeLineSet[judgelineCount + 1];
        Debug.Log(judgelineCount);
        for (int i = 0; i < judgelineCount + 1; i++)
        {
            chart.judgeLineList[i] = new JudgeLineSet();
            chart.judgeLineList[i].bpm = float.Parse(lines[1].Split(' ')[2]);
            chart.judgeLineList[i].rotateEvents = new valueSet[0];
            chart.judgeLineList[i].alphaEvents = new valueSet[0];
            chart.judgeLineList[i].moveEvents = new valueSet[0];
            chart.judgeLineList[i].speedEvents = new speedEvent[0];
        }
        Debug.Log($"judgelineCount+1={judgelineCount + 1}");
        for (int i = 0; i < judgelineCount + 1; i++)
        {//设置数据
            chart.judgeLineList[i].notesAbove = aboves[i].ToArray();
            chart.judgeLineList[i].notesBelow = belows[i].ToArray();
            speeds[i].Sort();
            moves[i].Sort();
            rotates[i].Sort();
            alphas[i].Sort();
#if !UNITY_EDITOR
            try
            { 
#endif
            //设置eventStart数值
            List<valueSet> ms = moves[i];
            List<valueSet> rs = rotates[i];
            List<valueSet> as1 = alphas[i];
            List<speedEvent> ses = speeds[i];
#if !UNITY_EDITOR
                try
                {
#endif
            
            //设置eventStart数值
            for (int j = 0; j < ms.Count; j++)
            {
                if (j == 0)
                {
                    ms[0].start = ms[0].end;
                    ms[0].start2 = ms[0].end2;
                    continue;
                }
                valueSet v = ms[j];
                if (float.IsNaN(v.start)) v.start = ms[j - 1].end;
                if (float.IsNaN(v.start2)) v.start2 = ms[j - 1].end2;
                ms[j] = v;
            }
            if (ms.Count == 0)
                ms.Add(new valueSet { startTime = 0, endTime = 9999, start = 0, end = 0, start2 = 0, end2 = 0 });
            else if (ms.Count == 1)
            {
                ms[0].endTime = 9999;
            }
            else ms.Add(new valueSet { startTime = ms[ms.Count - 1].endTime, endTime = 9999, start = ms[ms.Count - 1].end, end = ms[ms.Count - 1].end, start2 = ms[ms.Count - 1].end2, end2 = ms[ms.Count - 1].end2 });

            for (int j = 0; j < rs.Count; j++)
            {
                if (j == 0)
                {
                    rs[0].start = rs[0].end;
                    rs[0].start2 = rs[0].end2;
                    continue;
                }
                valueSet v = rs[j];
                if (float.IsNaN(v.start)) v.start = rs[j - 1].end;
                v.start2 = rs[j - 1].end2;
                rs[j] = v;
            }
            if (rs.Count == 0)
                rs.Add(new valueSet { startTime = 0, endTime = 9999, start = 0, end = 0, start2 = 0, end2 = 0 });
            else if (rs.Count == 1)
            {
                rs[0].endTime = 9999;
            }
            else rs.Add(new valueSet { startTime = rs[rs.Count - 1].endTime, endTime = 9999, start = rs[rs.Count - 1].end, end = rs[rs.Count - 1].end, start2 = rs[rs.Count - 1].end2, end2 = rs[rs.Count - 1].end2 });

            for (int j = 0; j < as1.Count; j++)
            {
                if (j == 0)
                {
                    as1[0].start = as1[0].end;
                    as1[0].start2 = as1[0].end2;
                    continue;
                }
                valueSet v = as1[j];
                if (float.IsNaN(v.start)) v.start = as1[j - 1].end;
                v.start2 = as1[j - 1].end2;
                as1[j] = v;
            }
            if (as1.Count == 0)
                as1.Add(new valueSet { startTime = 0, endTime = 9999, start = 0, end = 0, start2 = 0, end2 = 0 });
            else if (as1.Count == 1)
            {
                as1[0].endTime = 9999;
            }
            else as1.Add(new valueSet { startTime = as1[as1.Count - 1].endTime, endTime = 9999, start = as1[as1.Count - 1].end, end = as1[as1.Count - 1].end, start2 = as1[as1.Count - 1].end2, end2 = as1[as1.Count - 1].end2 });

            for (int j = 0; j < ses.Count - 1; j++)
            {
                if (ses.Count == 0 || ses.Count == 1) break;//assert
                speedEvent v = ses[j];
                v.endTime = ses[j + 1].startTime;
                ses[j] = v;
            }
            if (ses.Count == 1)
                ses[0].value = 1;
            if (ses.Count == 0)
                ses.Add(new speedEvent { startTime = 0, endTime = 9999, value = 1 });
            else if (ses.Count == 1)
            {
                ses[0].endTime = 9999;
            }
            else ses.Add(new speedEvent { startTime = ses[ses.Count - 1].endTime, endTime = 9999, value = ses[ses.Count - 1].value });
#if !UNITY_EDITOR
                }
                catch (Exception e) { Utils.AndroidToastStringShow(e.Message); }
#endif
            ms = FillValues(ms, bpm);
            rs = FillValues(rs, bpm);
            as1 = FillValues(as1, bpm);
            Debug.Log("Events填充完毕！！！！");
            //设置缓动
            if (true)
            {
                ms = EaseValues(ms, bpm);
                rs = EaseValues(rs, bpm);
                as1 = EaseValues(as1, bpm);
                ms = FillValues(ms, bpm, true);
                rs = FillValues(rs, bpm, true);
                as1 = FillValues(as1, bpm, true);
            }
            
            // ms = EaseValues(ms,bpm);
            chart.judgeLineList[i].moveEvents = ms.ToArray();
            chart.judgeLineList[i].rotateEvents = rs.ToArray();
            chart.judgeLineList[i].alphaEvents = as1.ToArray();
            chart.judgeLineList[i].speedEvents = ses.ToArray();
#if !UNITY_EDITOR
            }
            catch(Exception e)
            {
                Utils.AndroidToastStringShow(e.Message);
            }
#endif
        }

        return chart;
        }
    }
}